package com.ruoyi.system.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.KeyValueVo;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.utils.SecurityUtils;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.security.annotation.PreAuthorize;
import com.ruoyi.system.domain.SysRoleDept;
import com.ruoyi.system.domain.SysRoleMenu;
import com.ruoyi.system.domain.SysUserRole;
import com.ruoyi.system.service.ISysRoleDeptService;
import com.ruoyi.system.service.ISysRoleMenuService;
import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.system.service.ISysUserService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

/**
 * 角色信息
 *
 * @author ruoyi
 */
@RestController
@RequestMapping("/system/role")
public class SysRoleController extends com.ruoyi.common.core.web.controller.BaseController {
    @Autowired
    private ISysRoleService roleService;

    @Autowired
    private ISysRoleMenuService roleMenuService;

    @Autowired
    private ISysRoleDeptService roleDeptService;

    @Autowired
    private ISysUserService userService;

    @PreAuthorize
    //@PreAuthorize(hasPermi = "system:role:list")
    @GetMapping("/list")
    @ApiOperation("获取角色菜单列表（支持筛选,传表单数据）\n" +
            "(roleName-角色名称-String-非必填),\n" +
            "(roleKey-权限字符-String-非必填),\n" +
            "(status-状态（0正常 1停用）-String-非必填),\n" +
            "(dataScope-权限范围-String-非必填)")
    public com.ruoyi.common.core.web.page.TableDataInfo list(SysRole role) throws ClassNotFoundException {
        QueryWrapper<SysRole> wrapper = new QueryWrapper<>();
        if (role.getRoleName() != null) {
            wrapper.like(SysRole.ROLE_NAME, role.getRoleName());
        }
        if (role.getRoleKey() != null) {
            wrapper.like(SysRole.ROLE_KEY, role.getRoleKey());
        }
        if (role.getStatus() != null) {
            wrapper.like(SysRole.STATUS, role.getStatus());
        }
        if (role.getDataScope() != null) {
            wrapper.like(SysRole.DATA_SCOPE, role.getDataScope());
        }

        //系统管理员查看所有角色、部门成员查看属于本部门的角色
        if (!SysUser.isAdmin(SecurityUtils.getUserId())) {
            wrapper.eq(SysRole.DEPT_ID, SecurityUtils.getDeptId());
        }
        wrapper.orderByDesc(SysRole.CREATE_TIME);
        startPage();
        List<SysRole> list = roleService.list(wrapper);

        //构造角色与菜单关系的map
        List<SysRoleMenu> roleMenus = roleMenuService.list();
        HashMap<Long, HashSet<Long>> roleIdMenuIdsMap = new HashMap<>();
        Long roleId = roleMenus.get(0).getRoleId();
        HashSet<Long> menuIds = new HashSet<>();
        int flag = 0;
        for (SysRoleMenu roleMenu : roleMenus) {
            flag++;
            if (!roleId.equals(roleMenu.getRoleId())) {
                HashSet<Long> temp = new HashSet<>(menuIds);
                roleIdMenuIdsMap.put(roleId, temp);
                roleId = roleMenu.getRoleId();
                menuIds.clear();
                menuIds.add(roleMenu.getMenuId());
                //若循环执行到了最后，把最后一条key-value加入Map
                if (flag == roleMenus.size())
                    roleIdMenuIdsMap.put(roleId, menuIds);
                continue;
            }
            menuIds.add(roleMenu.getMenuId());
            //若循环执行到了最后，把最后一条key-value加入Map
            if (flag == roleMenus.size())
                roleIdMenuIdsMap.put(roleId, menuIds);
        }

        //构造角色与部门关系的map
        List<SysRoleDept> roleDepts = roleDeptService.list();
        HashMap<Long, HashSet<Long>> roleIdDeptIdsMap = new HashMap<>();
        Long role_Id = roleDepts.get(0).getRoleId();
        HashSet<Long> deptIds = new HashSet<>();
        int judge = 0;
        for (SysRoleDept roleDept : roleDepts) {
            judge++;
            if (!role_Id.equals(roleDept.getRoleId())) {
                HashSet<Long> temp = new HashSet<>(deptIds);
                roleIdDeptIdsMap.put(role_Id, temp);
                role_Id = roleDept.getRoleId();
                deptIds.clear();
                deptIds.add(roleDept.getDeptId());
                //若循环执行到了最后，把最后一条key-value加入Map
                if (judge == roleDepts.size())
                    roleIdDeptIdsMap.put(role_Id, deptIds);
                continue;
            }
            deptIds.add(roleDept.getDeptId());
            //若循环执行到了最后，把最后一条key-value加入Map
            if (judge == roleDepts.size())
                roleIdDeptIdsMap.put(role_Id, deptIds);
        }

        for (SysRole sysRole : list) {
            HashSet<Long> menu_Ids = roleIdMenuIdsMap.get(sysRole.getRoleId());
            sysRole.setMenuIds(menu_Ids != null ? Arrays.asList(menu_Ids.toArray(new Long[0])) : new ArrayList<>());
            HashSet<Long> dept_ids = roleIdDeptIdsMap.get(sysRole.getRoleId());
            sysRole.setDeptIds(dept_ids != null ? Arrays.asList(dept_ids.toArray(new Long[0])) : new ArrayList<>());
        }
        return getDataTable(list);
    }

    @PreAuthorize
    @ApiOperation("获取角色下拉列表")
    @GetMapping("/roleSelect")
    public com.ruoyi.common.core.web.domain.AjaxResult roleSelect(@RequestParam(value = "deptId", required = false) Long deptId) {
        QueryWrapper<SysRole> wrapper = new QueryWrapper<>();
        if (deptId != null) {
            wrapper.eq(SysRole.DEPT_ID, deptId);
        }
        List<SysRole> roleList = roleService.list(wrapper);
        ArrayList<KeyValueVo> vos = new ArrayList<>();
        roleList.forEach(item -> {
            KeyValueVo keyValueVo = new KeyValueVo();
            keyValueVo.setKey(item.getRoleId());
            keyValueVo.setValue(item.getRoleName());
            vos.add(keyValueVo);
        });
        return com.ruoyi.common.core.web.domain.AjaxResult.success(vos);
    }

    @Log(title = "角色管理", businessType = BusinessType.EXPORT)
    @PreAuthorize
    //@PreAuthorize(hasPermi = "system:role:export")
    @PostMapping(value="/export", produces = "application/octet-stream")
    @ApiOperation("导出角色信息")
    public void export(HttpServletResponse response, SysRole role) throws IOException {
        List<SysRole> list = roleService.selectRoleList(role);
        com.ruoyi.common.core.utils.poi.ExcelUtil<SysRole> util = new com.ruoyi.common.core.utils.poi.ExcelUtil<SysRole>(SysRole.class);
        util.exportExcel(response, list, "角色数据");
    }

    /**
     * 根据角色编号获取详细信息
     */
    @PreAuthorize
    //@PreAuthorize(hasPermi = "system:role:query")
    @GetMapping(value = "/{roleId}")
    @ApiOperation("根据角色ID获取详细信息\n" +
            "(roleId-角色ID-Long-必填)")
    public com.ruoyi.common.core.web.domain.AjaxResult getInfo(@PathVariable Long roleId) {
        roleService.checkRoleDataScope(roleId);
        SysRole sysRole = roleService.selectRoleById(roleId);
        List<SysRoleMenu> menuList = roleMenuService.list(new QueryWrapper<SysRoleMenu>()
                .eq(SysRoleMenu.ROLE_ID, roleId));
        ArrayList<Long> list = new ArrayList<>();
        for (SysRoleMenu menu : menuList) {
            list.add(menu.getMenuId());
        }
        sysRole.setMenuIds(list);
        return com.ruoyi.common.core.web.domain.AjaxResult.success(sysRole);
    }

    /**
     * 新增角色
     */
    @PreAuthorize
    //@PreAuthorize(hasPermi = "system:role:add")
    @Log(title = "角色管理", businessType = BusinessType.INSERT)
    @PostMapping
    @ApiOperation("新增角色\n" +
            "(roleName-角色名称-String-必填),\n" +
            "(roleKey-权限字符-String-必填),\n" +
            "(status-状态（0正常 1停用）-String-非必填),\n" +
            "(roleSort-角色顺序-String-必填),\n" +
            "(menuIds-菜单权限-Long[]-非必填),\n" +
            "(remark-备注-String-非必填)")
    public com.ruoyi.common.core.web.domain.AjaxResult add(@Validated @RequestBody SysRole role) {
        if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role))) {
            return com.ruoyi.common.core.web.domain.AjaxResult.error("新增角色'" + role.getRoleName() + "'失败，角色名称已存在");
        } else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role))) {
            return com.ruoyi.common.core.web.domain.AjaxResult.error("新增角色'" + role.getRoleName() + "'失败，角色权限已存在");
        }
        role.setCreateBy(SecurityUtils.getUsername());
        role.setDeptId(SecurityUtils.getDeptId());
        return toAjax(roleService.insertRole(role));
    }

    /**
     * 修改保存角色
     */
    @PreAuthorize
    //@PreAuthorize(hasPermi = "system:role:edit")
    @Log(title = "角色管理", businessType = BusinessType.UPDATE)
    @PutMapping
    @ApiOperation("修改保存角色\n" +
            "(roleId-角色ID-Long-必填)" +
            "(roleName-角色名称-String-必填),\n" +
            "(roleKey-权限字符-String-必填),\n" +
            "(status-状态（0正常 1停用）-String-非必填),\n" +
            "(roleSort-角色顺序-String-必填),\n" +
            "(menuIds-菜单权限-Long[]-非必填),\n" +
            "(remark-备注-String-非必填)")
    public com.ruoyi.common.core.web.domain.AjaxResult edit(@Validated @RequestBody SysRole role) {
        roleService.checkRoleAllowed(role);
        /*if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role))) {
            return AjaxResult.error("修改角色'" + role.getRoleName() + "'失败，角色名称已存在");
        } else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role))) {
            return AjaxResult.error("修改角色'" + role.getRoleName() + "'失败，角色权限已存在");
        }*/
        role.setUpdateBy(SecurityUtils.getUsername());
        return toAjax(roleService.updateRole(role));
    }

    /**
     * 修改保存数据权限
     */
    @PreAuthorize
    //@PreAuthorize(hasPermi = "system:role:edit")
    @Log(title = "角色管理", businessType = BusinessType.UPDATE)
    @PutMapping("/dataScope")
    @ApiOperation("修改保存数据权限," +
            "(dataScope-权限范围（1：所有数据权限；2：自定义数据权限；3：本部门数据权限；4：本部门及以下数据权限；5：仅本人数据权限）-String-必填),\n" +
            "(deptIds-数据权限-Long[]-必填)")
    public com.ruoyi.common.core.web.domain.AjaxResult dataScope(@RequestBody SysRole role) {
        if (role != null) {
            roleService.checkRoleAllowed(role);
            return toAjax(roleService.authDataScope(role));
        } else {
            return com.ruoyi.common.core.web.domain.AjaxResult.error("数据权限信息为空");
        }
    }

    /**
     * 状态修改
     */
    @PreAuthorize
    //@PreAuthorize(hasPermi = "system:role:edit")
    @Log(title = "角色管理", businessType = BusinessType.UPDATE)
    @PutMapping("/changeStatus")
    @ApiOperation("状态修改\n" +
            "(roleId-角色ID-Long-必填),\n" +
            "(status-角色状态（0正常 1停用）-String-必填)")
    public com.ruoyi.common.core.web.domain.AjaxResult changeStatus(@RequestBody SysRole role) {
        roleService.checkRoleAllowed(role);
        role.setUpdateBy(SecurityUtils.getUsername());
        return toAjax(roleService.updateRoleStatus(role));
    }

    /**
     * 删除角色
     */
    @PreAuthorize
    //@PreAuthorize(hasPermi = "system:role:remove")
    @Log(title = "角色管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{roleIds}")
    @ApiOperation("删除角色\n" +
            "(roleIds-角色ID-Long[]-必填)")
    public com.ruoyi.common.core.web.domain.AjaxResult remove(@PathVariable Long[] roleIds) {
        return toAjax(roleService.deleteRoleByIds(roleIds));
    }

    /**
     * 获取角色选择框列表
     */
    @PreAuthorize
    //@PreAuthorize(hasPermi = "system:role:query")
    @GetMapping("/optionselect")
    @ApiOperation("获取角色选择框列表")
    public com.ruoyi.common.core.web.domain.AjaxResult optionselect() {
        return com.ruoyi.common.core.web.domain.AjaxResult.success(roleService.selectRoleAll());
    }

    /**
     * 查询已分配用户角色列表
     */
    @PreAuthorize
    //@PreAuthorize(hasPermi = "system:role:list")
    @GetMapping("/authUser/allocatedList")
    @ApiOperation("查询已分配用户角色列表（支持筛选）\n" +
            "(userName-用户名称-String-非必填),\n" +
            "(phonenumber-手机号码-String-非必填)")
    public com.ruoyi.common.core.web.page.TableDataInfo allocatedList(SysUser user) {
        startPage();
        List<SysUser> list = userService.selectAllocatedList(user);
        return getDataTable(list);
    }

    /**
     * 查询未分配用户角色列表
     */
    @PreAuthorize
    //@PreAuthorize(hasPermi = "system:role:list")
    @GetMapping("/authUser/unallocatedList")
    @ApiOperation("查询未分配用户角色列表（支持筛选）\n" +
            "(userName-用户名称-String-非必填),\n" +
            "(phonenumber-手机号码-String-非必填)")
    public com.ruoyi.common.core.web.page.TableDataInfo unallocatedList(SysUser user) {
        startPage();
        List<SysUser> list = userService.selectUnallocatedList(user);
        return getDataTable(list);
    }

    /**
     * 取消授权用户
     */
    @PreAuthorize
    //@PreAuthorize(hasPermi = "system:role:edit")
    @Log(title = "角色管理", businessType = BusinessType.GRANT)
    @PutMapping("/authUser/cancel")
    @ApiOperation("取消授权用户\n" +
            "(userId-用户ID-Long-必填),\n" +
            "(roleId-角色ID-Long-必填)")
    public com.ruoyi.common.core.web.domain.AjaxResult cancelAuthUser(@RequestBody SysUserRole userRole) {
        return toAjax(roleService.deleteAuthUser(userRole));
    }

    /**
     * 批量取消授权用户
     */
    @PreAuthorize
    //@PreAuthorize(hasPermi = "system:role:edit")
    @Log(title = "角色管理", businessType = BusinessType.GRANT)
    @PutMapping("/authUser/cancelAll")
    @ApiOperation("批量取消授权用户\n" +
            "(userIds-用户ID数组-Long[]-必填),\n" +
            "(roleId-角色ID-Long-必填)")
    public com.ruoyi.common.core.web.domain.AjaxResult cancelAuthUserAll(Long roleId, Long[] userIds) {
        return toAjax(roleService.deleteAuthUsers(roleId, userIds));
    }

    /**
     * 为角色分配用户
     */
    @PreAuthorize
    //@PreAuthorize(hasPermi = "system:role:edit")
    @Log(title = "角色管理", businessType = BusinessType.GRANT)
    @PutMapping("/authUser/selectAll")
    @ApiOperation("为角色分配用户\n" +
            "(userIds-用户ID数组-Long[]-必填),\n" +
            "(roleId-角色ID-Long-必填)")
    public com.ruoyi.common.core.web.domain.AjaxResult selectAuthUserAll(Long roleId, Long[] userIds) {
        return toAjax(roleService.insertAuthUsers(roleId, userIds));
    }

    /**
     * 根据部门ID获取部门角色，0除外
     * @param deptId
     * @return
     */
    @GetMapping("/getDeptRolesByDeptId")
    public R<List<SysRole>> getDeptRolesByDeptId(@RequestParam("deptId") Long deptId){
        if(deptId==null||deptId==0L){
            List<SysRole> list = roleService.list(new QueryWrapper<SysRole>().eq(SysRole.ROLE_ID, 5L));
            return R.ok(list);
        }
        List<SysRole> list = roleService.list(new QueryWrapper<SysRole>().eq(SysRole.DEPT_ID, deptId).orderByAsc(SysRole.ROLE_TYPE).orderByAsc(SysRole.ROLE_SORT));
        return R.ok(list);

    }
}